package com.shockweb.common.serializable.binary;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.shockweb.common.International;
import com.shockweb.common.serializable.SerializableObject;
import com.shockweb.common.utils.classmethod.ClassMethod;
import com.shockweb.common.utils.classmethod.ClassMethodDefine;

/**
 * 将任意对象转化成二进制数据
 * 
 * @author 彭明华
 * 2017年12月19日 创建
 */
public class BinaryWriter{


	
    /**
     * 当前使用的class名和方法名定义
     */
    private Map<String,Byte> classNameDefines = new HashMap<String,Byte>();
    /**
     * 缓存类名字定义
     */
    private StringBuilder classNames = null;
    /**
     * 获取并设置class定义的索引
     * @param index
     * @param className
     */
    private byte getClassNameDefines(String name){
    	if(!classNameDefines.containsKey(name)){
    		if(classNames==null){
    			classNames = new StringBuilder(name);
    		}else{
    			classNames.append(",").append(name);
    		}
    		classNameDefines.put(name, (byte)(Byte.MIN_VALUE + classNameDefines.size()));
    	}
    	return classNameDefines.get(name);
    }
    
    /**
     * 当前使用的属性名定义
     */
    private Map<String,Short> nameDefines = new HashMap<String,Short>();
    /**
     * 缓存属性名定义
     */
    private StringBuilder names = null;
    /**
     * 返回和设置属性定义索引
     * @param index
     * @param className
     */
    private Short getNameDefines(String name){
    	if(!nameDefines.containsKey(name)){
    		if(names==null){
    			names = new StringBuilder(name);
    		}else{
    			names.append(',').append(name);
    		}
    		nameDefines.put(name, (short)(nameDefines.size() + Short.MIN_VALUE));
    	}
    	return nameDefines.get(name);
    }

    /**
     * 将instance串行化写入output
     * @param output
     * @param instance
     */
    public void writeInstance(OutputStream output,Object instance){
		try {
			writeInstance(instance);
			output.write(getDefines());
			output.write(binarys,0,binarysLen);
		} catch (Exception e) {
			throw new BinaryException(e);
		}
    }
    
    /**
     * 将任意对象转化成byte[]
     * @param instance 对象实例
     * @return byte[]
     * @throws BinaryException
     */
    public byte[] toBinarys(Object instance)throws BinaryException{
		try {
			writeInstance(instance);
			
			byte[] defines = getDefines();
			byte[] rtn = new byte[defines.length+binarysLen];
			SerializableObject.copyBytes(defines, rtn, 0);
			SerializableObject.copyBytes(binarys, rtn, defines.length);
    		return rtn;
		} catch (Exception e) {
			throw new BinaryException(e);
		}
    }
    
    /**
     * 写入对象
     * @param instance
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     * @throws IOException
     */
    private void writeInstance(Object instance) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
		classNameDefines.clear();
		classNames = null;
    	nameDefines.clear();
    	names = null;
    	binarysLen = 0;
		byte type = instanceType(instance);
		putBinarys(type);
		int start = binarysLen;
		binarysLen += BinaryReader.LEN_INTEGER;
		writeInstance(type,instance);
		setInteger(binarysLen-start-BinaryReader.LEN_INTEGER,start);
    }
    
    
    /**
     * 获取类名和属性名的定义
     * @return
     * @throws UnsupportedEncodingException
     */
    private byte[] getDefines() throws UnsupportedEncodingException{
		int len = BinaryReader.LEN_BYTE;
		len += BinaryReader.LEN_INTEGER;
		byte[] classNamesByte = null;
		if(classNames!=null && classNames.length()>0){
			classNamesByte = classNames.toString().getBytes(International.CHARSET);
			len += classNamesByte.length;
		}
		len += BinaryReader.LEN_INTEGER;
		byte[] namesByte = null;
		if(names!=null && names.length()>0){
			namesByte = names.toString().getBytes(International.CHARSET);
			len += namesByte.length;
		}
		
		byte[] define = new byte[len];
		int offset = 0;
		define[offset] = BinaryReader.LANUAGE_JAVA;
		offset += BinaryReader.LEN_BYTE;
		if(classNamesByte!=null){
			SerializableObject.copyBytes(SerializableObject.intToBytes(classNamesByte.length), define, offset);
			offset += BinaryReader.LEN_INTEGER;
			SerializableObject.copyBytes(classNamesByte, define, offset);
			offset += classNamesByte.length;
		}else{
			SerializableObject.copyBytes(SerializableObject.intToBytes(0), define, offset);
			offset += BinaryReader.LEN_INTEGER;
		}
		if(namesByte!=null){
			SerializableObject.copyBytes(SerializableObject.intToBytes(namesByte.length), define, offset);
			offset += BinaryReader.LEN_INTEGER;
			SerializableObject.copyBytes(namesByte, define, offset);
			offset += namesByte.length;
		}else{
			SerializableObject.copyBytes(SerializableObject.intToBytes(0), define, offset);
			offset += BinaryReader.LEN_INTEGER;
		}
		return define;
    }

    /**
     * 将任意对象按照type类型转化
     * @param type
     * @param instance
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IOException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     */
    public void writeInstance(byte type,Object instance) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, IllegalArgumentException, InvocationTargetException{
		if(type<=BinaryReader.TYPE_CUSTOM){
			writeCustomClass(instance);
		}else{
	    	switch(type){
	    		case BinaryReader.TYPE_LIST:
	    			writeList(instance);
	    			return;
	    		case BinaryReader.TYPE_MAP:
	    			writeMap(instance);
	    			return;
	    		case BinaryReader.TYPE_ARRAY:
	    			writeArray(instance);
	    			return;
	    		default:
	    			writeValue(type,instance);
	    	}
		}
    }
	
    /**
     * 获取class的预先定义的数据类型
     * @param instance
     * @return
     */
    private static byte classType(Class<?> cls){
        if(String.class.equals(cls))
            return BinaryReader.TYPE_STRING;
        if(int.class.equals(cls))
            return BinaryReader.TYPE_int;
        if(Integer.class.equals(cls))
        	return BinaryReader.TYPE_INTEGER;
        if(long.class.equals(cls))
            return BinaryReader.TYPE_long;
        if(Long.class.equals(cls))
            return BinaryReader.TYPE_LONG;
        if(BigDecimal.class.equals(cls))
        	return BinaryReader.TYPE_BIGDECIMAL;
        if(double.class.equals(cls))
            return BinaryReader.TYPE_double;
        if(Double.class.equals(cls))
        	return BinaryReader.TYPE_DOUBLE;
        if(float.class.equals(cls))
        	return BinaryReader.TYPE_float;
        if(Float.class.equals(cls))
        	return BinaryReader.TYPE_FLOAT;
        if(short.class.equals(cls))
            return BinaryReader.TYPE_short;
        if(Short.class.equals(cls))
            return BinaryReader.TYPE_SHORT;
        if(boolean.class.equals(cls))
            return BinaryReader.TYPE_boolean;
        if(Boolean.class.equals(cls))
            return BinaryReader.TYPE_BOOLEAN;
        if(byte.class.equals(cls))
            return BinaryReader.TYPE_byte;
        if(Byte.class.equals(cls))
            return BinaryReader.TYPE_BYTE;
        if(char.class.equals(cls))
            return BinaryReader.TYPE_char;
        if(Character.class.equals(cls))
            return BinaryReader.TYPE_CHARACTER;
        if(Date.class.equals(cls))
            return BinaryReader.TYPE_DATE;
        if(java.sql.Date.class.equals(cls))
            return BinaryReader.TYPE_SQLDATE;
        if(Time.class.equals(cls))
            return BinaryReader.TYPE_TIME;
        if(Timestamp.class.equals(cls))
            return BinaryReader.TYPE_TIMESTAMP;
        if(boolean.class.equals(cls))
            return BinaryReader.TYPE_boolean;
        if(Boolean.class.equals(cls))
            return BinaryReader.TYPE_BOOLEAN;
        if(Object.class.equals(cls))
            return BinaryReader.TYPE_OBJECT;
        if(StringBuffer.class.equals(cls))
        	return BinaryReader.TYPE_STRINGBUFFER;
        if(StringBuilder.class.equals(cls))
        	return BinaryReader.TYPE_STRINGBUILDER;
        if(Class.class.equals(cls))
        	return BinaryReader.TYPE_CLASS;
        if(cls.isAssignableFrom(List.class))
			return BinaryReader.TYPE_LIST;
        if(cls.isAssignableFrom(Map.class))
			return BinaryReader.TYPE_MAP;
        if(BigInteger.class.equals(cls))
        	return BinaryReader.TYPE_BIGINTEGER;
        if(cls.isArray())
        	return BinaryReader.TYPE_ARRAY;
        return BinaryReader.TYPE_CUSTOM;
    }
    
    /**
     * 获取实例的数据类型
     * @param instance
     * @return
     */
    private static byte instanceType(Object instance){
    	if(instance==null)
    		return BinaryReader.TYPE_NULL;
    	Class<?> cls = instance.getClass();
        if(Object.class.equals(cls))
            return BinaryReader.TYPE_OBJECT;
		if(instance instanceof List<?>)
			return BinaryReader.TYPE_LIST;
		if(instance instanceof Map<?,?>)
			return BinaryReader.TYPE_MAP;
        if(String.class.equals(cls))
            return BinaryReader.TYPE_STRING;
        if(int.class.equals(cls))
            return BinaryReader.TYPE_int;
        if(Integer.class.equals(cls))
        	return BinaryReader.TYPE_INTEGER;
        if(long.class.equals(cls))
            return BinaryReader.TYPE_long;
        if(Long.class.equals(cls))
            return BinaryReader.TYPE_LONG;
        if(StringBuffer.class.equals(cls))
        	return BinaryReader.TYPE_STRINGBUFFER;
        if(StringBuilder.class.equals(cls))
        	return BinaryReader.TYPE_STRINGBUILDER;
        if(BigDecimal.class.equals(cls))
        	return BinaryReader.TYPE_BIGDECIMAL;
        if(double.class.equals(cls))
            return BinaryReader.TYPE_double;
        if(Double.class.equals(cls))
        	return BinaryReader.TYPE_DOUBLE;
        if(float.class.equals(cls))
        	return BinaryReader.TYPE_float;
        if(Float.class.equals(cls))
        	return BinaryReader.TYPE_FLOAT;
        if(short.class.equals(cls))
            return BinaryReader.TYPE_short;
        if(Short.class.equals(cls))
            return BinaryReader.TYPE_SHORT;
        if(boolean.class.equals(cls))
            return BinaryReader.TYPE_boolean;
        if(Boolean.class.equals(cls))
            return BinaryReader.TYPE_BOOLEAN;
        if(byte.class.equals(cls))
            return BinaryReader.TYPE_byte;
        if(Byte.class.equals(cls))
            return BinaryReader.TYPE_BYTE;
        if(char.class.equals(cls))
            return BinaryReader.TYPE_char;
        if(Character.class.equals(cls))
            return BinaryReader.TYPE_CHARACTER;
        if(Date.class.equals(cls))
            return BinaryReader.TYPE_DATE;
        if(java.sql.Date.class.equals(cls))
            return BinaryReader.TYPE_SQLDATE;
        if(Time.class.equals(cls))
            return BinaryReader.TYPE_TIME;
        if(Timestamp.class.equals(cls))
            return BinaryReader.TYPE_TIMESTAMP;
        if(boolean.class.equals(cls))
            return BinaryReader.TYPE_boolean;
        if(Boolean.class.equals(cls))
            return BinaryReader.TYPE_BOOLEAN;
        if(BigInteger.class.equals(cls))
        	return BinaryReader.TYPE_BIGINTEGER;
        if(Class.class.equals(cls))
        	return BinaryReader.TYPE_CLASS;
        if(cls.isArray()){
        	return BinaryReader.TYPE_ARRAY;
        }
        return BinaryReader.TYPE_CUSTOM;
    }
    
   /**
    * 转化数组对象
    * @param instance
    * @throws ClassNotFoundException
    * @throws InstantiationException
    * @throws IllegalAccessException
    * @throws IllegalArgumentException
    * @throws InvocationTargetException
    * @throws IOException
    */
    private void writeArray(Object instance) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
		Class<?> cls = instance.getClass();
		byte dim = 0;
    	Class<?> c = cls;
    	while(c.isArray()){
    		c = c.getComponentType();
    		dim++;
    	}
    	putBinarys(dim);
    	byte dimType = classType(c);
    	if(dimType <= BinaryReader.TYPE_CUSTOM || dimType == BinaryReader.TYPE_LIST || dimType == BinaryReader.TYPE_MAP){
            String className = c.getName();
            dimType = getClassNameDefines(className);
    	}
    	byte type = classType(cls.getComponentType());
       	switch(type){
	        case BinaryReader.TYPE_STRING:
	        	String[] strValues = (String[])instance;
	        	putInteger(strValues.length);
	        	putBinarys(dimType);
	        	for(String value:strValues){
	        		byte[] bytes = value.getBytes(International.CHARSET);
	        		putInteger(bytes.length);
	        		putBinarys(bytes);
	        	}
	        	break;
	        case BinaryReader.TYPE_int:
	        	int[] intValues = (int[])instance;
	        	putInteger(intValues.length);
	        	putBinarys(dimType);
	        	for(int value:intValues){
	        		putInteger(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_INTEGER:
	        	Integer[] integerValues = (Integer[])instance;
	        	putInteger(integerValues.length);
	        	putBinarys(dimType);
	        	for(Integer value:integerValues){
	        		putInteger(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_long:
	        	long[] lValues = (long[])instance;
	        	putInteger(lValues.length);
	        	putBinarys(dimType);
	        	for(long value:lValues){
	        		putLong(value);
	        	}
	        case BinaryReader.TYPE_LONG:
	        	Long[] longValues = (Long[])instance;
	        	putInteger(longValues.length);
	        	putBinarys(dimType);
	        	for(Long value:longValues){
	        		putLong(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_short:
	        	short[] sValues = (short[])instance;
	        	putInteger(sValues.length);
	        	putBinarys(dimType);
	        	for(short value:sValues){
	        		putShort(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_SHORT:
	        	Short[] shortValues = (Short[])instance;
	        	putInteger(shortValues.length);
	        	putBinarys(dimType);
	        	for(Short value:shortValues){
	        		putShort(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_BIGDECIMAL:
	        	BigDecimal[] bigIntValues = (BigDecimal[])instance;
	        	putInteger(bigIntValues.length);
	        	putBinarys(dimType);
	        	for(BigDecimal value:bigIntValues){
	        		byte[] bytes = value.toString().getBytes(International.CHARSET);
	        		putInteger(bytes.length);
	        		putBinarys(bytes);
	        	}
	        	break;
	        case BinaryReader.TYPE_double:
	        	double[] dValues = (double[])instance;
	        	putInteger(dValues.length);
	        	putBinarys(dimType);
	        	for(double value:dValues){
	        		putDouble(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_DOUBLE:
	        	Double[] doubleValues = (Double[])instance;
	        	putInteger(doubleValues.length);
	        	putBinarys(dimType);
	        	for(Double value:doubleValues){
	        		putDouble(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_float:
	        	float[] fValues = (float[])instance;
	        	putInteger(fValues.length);
	        	putBinarys(dimType);
	        	for(float value:fValues){
	        		putFloat(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_FLOAT:
	        	Float[] floatValues = (Float[])instance;
	        	putInteger(floatValues.length);
	        	putBinarys(dimType);
	        	for(Float value:floatValues){
	        		putFloat(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_byte:
	        	byte[] bValues = (byte[])instance;
	        	putInteger(bValues.length);
	        	putBinarys(dimType);
	        	putBinarys(bValues);
	        	break;
	        case BinaryReader.TYPE_BYTE:
	        	Byte[] byteValues = (Byte[])instance;
	        	putInteger(byteValues.length);
	        	putBinarys(dimType);
	        	for(Byte value:byteValues){
	        		putBinarys(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_char:
	        	char[] cValues = (char[])instance;
	        	putInteger(cValues.length);
	        	putBinarys(dimType);
	        	for(char value:cValues){
	        		putChar(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_CHARACTER:
	        	Character[] charValues = (Character[])instance;
	        	putInteger(charValues.length);
	        	putBinarys(dimType);
	        	for(Character value:charValues){
	        		putChar(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_DATE:
	        	Date[] dateValues = (Date[])instance;
	        	putInteger(dateValues.length);
	        	putBinarys(dimType);
	        	for(Date value:dateValues){
	        		putLong(value.getTime());
	        	}
	        	break;
	        case BinaryReader.TYPE_SQLDATE:
	        	java.sql.Date[] sqlDateValues = (java.sql.Date[])instance;
	        	putInteger(sqlDateValues.length);
	        	putBinarys(dimType);
	        	for(java.sql.Date value:sqlDateValues){
	        		putLong(value.getTime());
	        	}
	        	break;
	        case BinaryReader.TYPE_TIME:
	        	Time[] timeValues = (Time[])instance;
	        	putInteger(timeValues.length);
	        	putBinarys(dimType);
	        	for(Time value:timeValues){
	        		putLong(value.getTime());
	        	}
	        	break;
	        case BinaryReader.TYPE_TIMESTAMP:
	        	Timestamp[] timestampValues = (Timestamp[])instance;
	        	putInteger(timestampValues.length);
	        	putBinarys(dimType);
	        	for(Timestamp value:timestampValues){
	        		putLong(value.getTime());
	        	}
	        	break;
	        case BinaryReader.TYPE_boolean:
	        	boolean[] boolValues = (boolean[])instance;
	        	putInteger(boolValues.length);
	        	putBinarys(dimType);
	        	for(boolean value:boolValues){
	        		putBoolean(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_BOOLEAN:
	        	Boolean[] booleanValues = (Boolean[])instance;
	        	putInteger(booleanValues.length);
	        	putBinarys(dimType);
	        	for(Boolean value:booleanValues){
	        		putBoolean(value);
	        	}
	        	break;
	        case BinaryReader.TYPE_BIGINTEGER:
	        	BigInteger[] bingIntValues = (BigInteger[])instance;
	        	putInteger(bingIntValues.length);
	        	putBinarys(dimType);
	        	for(BigInteger value:bingIntValues){
	        		byte[] bytes = value.toString().getBytes(International.CHARSET);
	        		putInteger(bytes.length);
	        		putBinarys(bytes);
	        	}
	        	break;
	        case BinaryReader.TYPE_STRINGBUFFER:
	        	StringBuffer[] sbIntValues = (StringBuffer[])instance;
	        	putInteger(sbIntValues.length);
	        	putBinarys(dimType);
	        	for(StringBuffer value:sbIntValues){
	        		byte[] bytes = value.toString().getBytes(International.CHARSET);
	        		putInteger(bytes.length);
	        		putBinarys(bytes);
	        	}
	        	break;
	        case BinaryReader.TYPE_STRINGBUILDER:
	        	StringBuilder[] sbdIntValues = (StringBuilder[])instance;
	        	putInteger(sbdIntValues.length);
	        	putBinarys(dimType);
	        	for(StringBuilder value:sbdIntValues){
	        		byte[] bytes = value.toString().getBytes(International.CHARSET);
	        		putInteger(bytes.length);
	        		putBinarys(bytes);
	        	}
	        	break;
	        case BinaryReader.TYPE_CLASS:
	        	Class[] sbdClassValues = (Class[])instance;
	        	putInteger(sbdClassValues.length);
	        	putBinarys(dimType);
	        	for(Class value:sbdClassValues){
	        		byte t = classType(value);
	            	if(t <= BinaryReader.TYPE_CUSTOM || t == BinaryReader.TYPE_LIST || t == BinaryReader.TYPE_MAP || t == BinaryReader.TYPE_ARRAY){
	                    String className = value.getName();
	                    t = getClassNameDefines(className);
	            	}
	            	putBinarys(t);
	        	}
	        	break;
	        case BinaryReader.TYPE_LIST:
	        	List[] listValues = (List[])instance;
	        	putInteger(listValues.length);
	        	for(List value:listValues){
	        		type = instanceType(value);
	        		putBinarys(type);
	            	int typeLen = BinaryReader.typeLen(type);
	            	if(typeLen>=0){
	            		writeInstance(type,value);
	            	}else{
	            		int start = binarysLen;
	            		binarysLen += BinaryReader.LEN_INTEGER;
	
		        		writeList(value);
		        		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
	            	}
	        	}
	        	break;
	        case BinaryReader.TYPE_MAP:
	        	Map[] mapValues = (Map[])instance;
	        	putInteger(mapValues.length);
	        	for(Map value:mapValues){
	        		type = instanceType(value);
	        		putBinarys(type);
	            	int typeLen = BinaryReader.typeLen(type);
	            	if(typeLen>=0){
	            		writeInstance(type,value);
	            	}else{
	            		int start = binarysLen;
	            		binarysLen += BinaryReader.LEN_INTEGER;
	
		        		writeMap(value);
		        		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
	            	}
	        	}
	        	break;
	        case BinaryReader.TYPE_OBJECT:
	        	Object[] values = (Object[])instance;
	        	putInteger(values.length);
	        	putBinarys(dimType);
	        	for(Object value:values){
	        		byte t = instanceType(value);
	
	            	int typeLen = BinaryReader.typeLen(t);
	            	if(typeLen>=0){
	    				putBinarys(t);
	    				writeInstance(t,value);
	            	}else{
	    				putBinarys(t);
	    				int start = binarysLen;
	    				binarysLen += BinaryReader.LEN_INTEGER;
	
	            		writeInstance(t,value);
	            		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
	    			}
	        	}
	        	break;
	        case BinaryReader.TYPE_ARRAY:
	        	Object[] arrayValues = (Object[])instance;
	        	putInteger(arrayValues.length);
	        	putBinarys(dimType);
	        	for(Object value:arrayValues){
	        		type = instanceType(value);
	        		putBinarys(type);
	        		
	            	int typeLen = BinaryReader.typeLen(type);
	            	if(typeLen>=0){
	            		writeInstance(type,value);
	            	}else{
	            		int start = binarysLen;
	            		binarysLen += BinaryReader.LEN_INTEGER;
	
		        		writeInstance(type,value);
		        		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
	            	}
	        	}
	        	break;
	        case BinaryReader.TYPE_CUSTOM:
	        	Object[] ctValues = (Object[])instance;
	        	putInteger(ctValues.length);
	        	putBinarys(dimType);
	        	for(Object value:ctValues){
	        		type = instanceType(value);
	        		putBinarys(type);
	            	int typeLen = BinaryReader.typeLen(type);
	            	if(typeLen>=0){
	            		writeInstance(type,value);
	            	}else{
	            		int start = binarysLen;
	            		binarysLen += BinaryReader.LEN_INTEGER;
	
		        		writeInstance(type,value);
		        		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
	            	}
	        	}
	        	break;
	        default:
	        	throw new BinaryException("非法的数据类型type" + type);
    	}
    }
	   
	/**
	 * 转化List对象
	 * @param instance
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws IOException
	 */
	private void writeList(Object instance) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
        String className = instance.getClass().getName();
        byte classIndex = getClassNameDefines(className);
        putBinarys(classIndex);

        for(Object value:(List<?>)instance){
        	byte type = instanceType(value);
        	int typeLen = BinaryReader.typeLen(type);
        	putBinarys(type);
        	if(typeLen>=0){
        		writeInstance(type,value);
        	}else{
        		int start = binarysLen;
        		binarysLen += BinaryReader.LEN_INTEGER;

        		writeInstance(type,value);
        		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
        	}
        }
	}

   /**
    * 转化Map对象
    * @param instance
    * @throws ClassNotFoundException
    * @throws InstantiationException
    * @throws IllegalAccessException
    * @throws IllegalArgumentException
    * @throws InvocationTargetException
    * @throws IOException
    */
    private void writeMap(Object instance) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
    	
        String className = instance.getClass().getName();
        byte classIndex = getClassNameDefines(className);
        putBinarys(classIndex);
        
        Map map = (Map)instance;
        Iterator<Entry<?,?>> entrys = map.entrySet().iterator();
    	while(entrys.hasNext()){
    		Entry<?,?> entry = entrys.next();
    		byte type = instanceType(entry.getKey());
    		putBinarys(type);
    		
        	int typeLen = BinaryReader.typeLen(type);
        	if(typeLen>=0){
        		writeInstance(type,entry.getKey());
        	}else{
        		int start = binarysLen;
        		binarysLen += BinaryReader.LEN_INTEGER;

	    		writeInstance(type,entry.getKey());
	    		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
        	}
        	
        	type = instanceType(entry.getValue());
        	putBinarys(type);
        	
        	typeLen = BinaryReader.typeLen(type);
        	if(typeLen>=0){
        		writeInstance(type,entry.getValue());
        	}else{
        		int start = binarysLen;
        		binarysLen += BinaryReader.LEN_INTEGER;
	    		
	    		type = instanceType(entry.getValue());
	    		writeInstance(type,entry.getValue());
	    		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
        	}
        }

    }
  
    /**
     * 转化自定义对象
     * @param instance
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     * @throws IOException
     */
    private void writeCustomClass(Object instance) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
        String className = instance.getClass().getName();
        byte classIndex = getClassNameDefines(className);
        putBinarys(classIndex);

        List<ClassMethodDefine> methods = ClassMethod.getGetMethods(instance.getClass());
    	for(int i=0;i<methods.size();i++){
    		short nameIndex = getNameDefines(methods.get(i).getName());
    		putShort(nameIndex);

    		ClassMethodDefine getMethod = methods.get(i);
    		Method m = getMethod.getMethod();
    		Object value = m.invoke(instance);
    		
    		byte type = instanceType(value);
    		putBinarys(type);
    		
    		int typeLen = BinaryReader.typeLen(type);
        	if(typeLen>=0){
        		writeInstance(type,value);
        	}else{
        		int start = binarysLen;
        		binarysLen += BinaryReader.LEN_INTEGER;
	        	
	    		writeInstance(type,value);
	    		setInteger(binarysLen - start - BinaryReader.LEN_INTEGER, start);
        	}
    	}

    }
    
    /**
     * 转化基本Java对象
     * @param type
     * @param instance
     * @throws IOException
     */
    private void writeValue(byte type,Object instance) throws IOException{
    	byte[] bytes = null;
    	switch(type){
	        case BinaryReader.TYPE_NULL:
	        	break;
	        case BinaryReader.TYPE_STRING:
	        	bytes = ((String)instance).getBytes(International.CHARSET);
	        	putBinarys(bytes);
	        	break;
	        case BinaryReader.TYPE_BIGDECIMAL:
	        	bytes = ((BigDecimal)instance).toString().getBytes(International.CHARSET);
	        	putBinarys(bytes);
	        	break;
	        case BinaryReader.TYPE_double:
	        	putDouble((Double)instance);
	        	break;
	        case BinaryReader.TYPE_DOUBLE:
	        	putDouble((Double)instance);
	        	break;
	        case BinaryReader.TYPE_float:
	        	putFloat((Float)instance);
	        	break;
	        case BinaryReader.TYPE_FLOAT:
	        	putFloat((Float)instance);
	        	break;
	        case BinaryReader.TYPE_int:
	        	putInteger((Integer)instance);
	        	break;
	        case BinaryReader.TYPE_INTEGER:
	        	putInteger((Integer)instance);
	        	break;
	        case BinaryReader.TYPE_long:
	        	putLong((Long)instance);
	        	break;
	        case BinaryReader.TYPE_LONG:
	        	putLong((Long)instance);
	        	break;
	        case BinaryReader.TYPE_short:
	        	putShort((Short)instance);
	        	break;
	        case BinaryReader.TYPE_SHORT:
	        	putShort((Short)instance);
	        	break;
	        case BinaryReader.TYPE_byte:
	        	putBinarys((Byte)instance);
	        	break;
	        case BinaryReader.TYPE_BYTE:
	        	putBinarys((Byte)instance);
	        	break;
	        case BinaryReader.TYPE_char:
	        	putChar((Character)instance);
	        	break;
	        case BinaryReader.TYPE_CHARACTER:
	        	putChar((Character)instance);
	        	break;
	        case BinaryReader.TYPE_DATE:
	        	putLong(((Date)instance).getTime());
	        	break;
	        case BinaryReader.TYPE_SQLDATE:
	        	putLong(((java.sql.Date)instance).getTime());
	        	break;
	        case BinaryReader.TYPE_TIME:
	        	putLong(((Time)instance).getTime());
	        	break;
	        case BinaryReader.TYPE_TIMESTAMP:
	        	putLong(((Timestamp)instance).getTime());
	        	break;
	        case BinaryReader.TYPE_boolean:
	        	putBoolean((Boolean)instance);
	        	break;
	        case BinaryReader.TYPE_BOOLEAN:
	        	putBoolean((Boolean)instance);
	        	break;
	        case BinaryReader.TYPE_BIGINTEGER:
	        	bytes = ((BigInteger)instance).toString().getBytes(International.CHARSET);
	        	putBinarys(bytes);
	        	break;
	        case BinaryReader.TYPE_STRINGBUFFER:
	        	bytes = ((StringBuffer)instance).toString().getBytes(International.CHARSET);
	        	putBinarys(bytes);
	        	break;
	        case BinaryReader.TYPE_STRINGBUILDER:
	        	bytes = ((StringBuilder)instance).toString().getBytes(International.CHARSET);
	        	putBinarys(bytes);
	        	break;
	        case BinaryReader.TYPE_CLASS:
        		byte t = classType((Class)instance);
            	if(t <= BinaryReader.TYPE_CUSTOM || t == BinaryReader.TYPE_LIST || t == BinaryReader.TYPE_MAP || t == BinaryReader.TYPE_ARRAY){
                    String className = ((Class)instance).getName();
                    t = getClassNameDefines(className);
            	}
            	putBinarys(t);
	        	break;
	        case BinaryReader.TYPE_OBJECT:
	        	break;
	        default:
	        	throw new BinaryException("非法的数据类型type" + type);
        }
    }
    
    /**
     * 缓存转化后的byte[]
     */
    private byte[] binarys = new byte[4096];
    /**
     * 写入binarys的实际长度
     */
    private int binarysLen = 0;

    
    /**
     * 多个字节写入binarys
     * @param bytes
     */
    private void putBinarys(byte[] bytes){
    	int size = 0;
    	while(binarys.length + size < binarysLen + bytes.length){
    		size += 2048;
    	}
    	if(size>0){
    		byte[] tmp = new byte[binarys.length + size];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
    	SerializableObject.copyBytes(bytes, binarys, binarysLen);
		binarysLen += bytes.length;
    }
    
    /**
     * 单字节写入binarys
     * @param b
     */
    private void putBinarys(byte b){
    	if(binarysLen+1>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
    	binarys[binarysLen] = b;
		binarysLen ++;
    }
    

    /**
     * boolean写入binarys
     */
    private void putBoolean(boolean b) {
    	if(binarysLen+1>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
        if (b) {
        	binarys[binarysLen] = -1;
        } else {
        	binarys[binarysLen] = 0;
        }
		binarysLen ++;
    }
    
    /**
     * char写入binarys
     */
    private void putChar(char c) {
    	if(binarysLen+2>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
    	binarys[binarysLen] = (byte) ((c & 0xFF00) >> 8);
    	binarys[binarysLen+1] = (byte) (c & 0xFF);
		binarysLen += 2;
    }
    
    /**
     * short写入binarys
     */
    private void putShort(short i) {
    	if(binarysLen+2>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
    	binarys[binarysLen] = (byte) ((i >> 8) & 0xFF);
    	binarys[binarysLen+1] = (byte) (i & 0xFF);
		binarysLen += 2;
    }

    /**
     * int写入binarys
     */
    private void putInteger(int i) {
    	if(binarysLen+4>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
    	binarys[binarysLen] = (byte) ((i >> 24) & 0xFF);
    	binarys[binarysLen+1] = (byte) ((i >> 16) & 0xFF);
    	binarys[binarysLen+2] = (byte) ((i >> 8) & 0xFF);
    	binarys[binarysLen+3] = (byte) (i & 0xFF);
		binarysLen += 4;
    }
    
    /**
     * int写入binarys指定的区域
     */
    private void setInteger(int i,int offset) {
    	binarys[offset] = (byte) ((i >> 24) & 0xFF);
    	binarys[offset+1] = (byte) ((i >> 16) & 0xFF);
    	binarys[offset+2] = (byte) ((i >> 8) & 0xFF);
    	binarys[offset+3] = (byte) (i & 0xFF);
    }
    
    
    /**
     * long写入binarys
     * @param i
     * @return
     */
    private void putLong(long i) {
    	if(binarysLen+8>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
    	binarys[binarysLen] = (byte) ((i >> 56) & 0xFF);
    	binarys[binarysLen+1] = (byte) ((i >> 48) & 0xFF);
    	binarys[binarysLen+2] = (byte) ((i >> 40) & 0xFF);
    	binarys[binarysLen+3] = (byte) ((i >> 32) & 0xFF);
    	binarys[binarysLen+4] = (byte) ((i >> 24) & 0xFF);
    	binarys[binarysLen+5] = (byte) ((i >> 16) & 0xFF);
    	binarys[binarysLen+6] = (byte) ((i >> 8) & 0xFF);
    	binarys[binarysLen+7] = (byte) (i & 0xFF);
		binarysLen += 8;
    }
    
    
    /**
     * double写入binarys
     * @param i
     * @return
     */
    private void putDouble(double d) {
    	if(binarysLen+8>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
		long v = Double.doubleToLongBits(d);  
		binarys[binarysLen] = (byte)(v >>> 56);  
		binarys[binarysLen+1] = (byte)(v >>> 48);  
		binarys[binarysLen+2] = (byte)(v >>> 40);  
		binarys[binarysLen+3] = (byte)(v >>> 32);  
		binarys[binarysLen+4] = (byte)(v >>> 24);  
		binarys[binarysLen+5] = (byte)(v >>> 16);  
		binarys[binarysLen+6] = (byte)(v >>>  8);  
		binarys[binarysLen+7] = (byte)(v >>>  0);  
		binarysLen += 8;
    }

    /**
     * float写入binarys
     * @param i
     * @return
     */
    private void putFloat(float i) {
    	if(binarysLen+4>=binarys.length){
    		byte[] tmp = new byte[binarys.length + 2048];
    		SerializableObject.copyBytes(binarys, tmp, 0,binarysLen);
    		binarys = tmp;
    	}
		long v = Float.floatToIntBits(i);
		binarys[binarysLen] = (byte)(v >>> 24);  
		binarys[binarysLen+1] = (byte)(v >>> 16);  
		binarys[binarysLen+2] = (byte)(v >>> 8);  
		binarys[binarysLen+3] = (byte)(v >>> 0);  
		binarysLen += 4;
    }
}